﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Intorise.Net;
using Intorise.Common;
using System.Drawing;
using System.Net;
using Config;

namespace Model
{
    public class DataPackager
    {
        static NetTools net = new NetTools();
        static Dictionary<string, IAttactDataPack> attactDataPacker = new Dictionary<string, IAttactDataPack>();
        static bool LogServerInfo = false;


        static DataPackager()
        {
            attactDataPacker.Add("黑龙波", new HLB());
            attactDataPacker.Add("陨石术", new YSS());
            attactDataPacker.Add("霹雳回旋斩", new PLHXZ());
            attactDataPacker.Add("霹雳地裂斩", new PLDLZ());
            attactDataPacker.Add("地狱火", new DYH());
            attactDataPacker.Add("穿透箭", new CTJ());
            LogServerInfo = ((MainConfig)ConfigManager.ApplicationConfig).LogServerInfo;
        }

        /// <summary>
        /// 获取传送数据
        /// </summary>
        /// <param name="map"></param>
        /// <returns></returns>
        public static byte[] GetTransmitData(Map map)
        {
            var command = Commands.GetCommand("传送");
            var data = Tools.Contact(command.Data, map.Data, new byte[] { 0x0c, 0 });
            return Tools.Contact(net.GetNetworkBytes(data.Length), data);
        }

        /// <summary>
        /// 获取移动路径数据
        /// </summary>
        /// <param name="source">源地址坐标</param>
        /// <param name="target">目的地址坐标</param>
        /// <returns></returns>
        public static byte[] GetWalkData(Point source, Point target, int steep = 6)
        {
            List<byte> data = new List<byte>();

            int a, b, c;
            int x = target.X;
            int y = target.Y;
            a = x - source.X;
            b = y - source.Y;

            int count = Math.Min(Math.Abs(a) / steep, Math.Abs(b) / steep);

            #region x,y都走
            for (int i = 0; i < count; i++)
            {
                data.Add(GetSteep(a, b, steep));
            }
            #endregion


            ComputeLevel(ref a, ref b, count * steep);//计算还剩下的距离

            if (a != 0 && b != 0)
            {
                c = Math.Min(Math.Abs(a), Math.Abs(b));
                data.Add(GetSteep(a, b, c));
                ComputeLevel(ref a, ref b, c);//计算还剩下的距离
            }

            count = Math.Max(Math.Abs(a) / steep, Math.Abs(b) / steep);

            for (int i = 0; i < count; i++)
            {
                data.Add(GetSteep(a, b, steep));
            }
            ComputeLevel(ref a, ref b, count * steep);
            c = Math.Max(Math.Abs(a), Math.Abs(b));
            data.Add(GetSteep(a, b, c));

            var datas = Tools.Contact(new byte[] { 0x00, 0x01, 0x8B, 0x51 }, net.GetNetworkBytes((short)(source.X * 25)),
                net.GetNetworkBytes((short)(source.Y * 25)),
                net.GetNetworkBytes((short)data.Count), data.ToArray());
            datas = Tools.Contact(net.GetNetworkBytes(datas.Length), datas);
            return datas;
        }

        public static byte[] GetWalkData(short locationX, short locationY, Point target, int steep = 6)
        {
            List<byte> data = new List<byte>();

            int a, b, c;
            int x = target.X;
            int y = target.Y;
            a = x - locationX / 25;
            b = y - locationY / 25;

            int count = Math.Min(Math.Abs(a) / steep, Math.Abs(b) / steep);

            #region x,y都走
            for (int i = 0; i < count; i++)
            {
                data.Add(GetSteep(a, b, steep));
            }
            #endregion


            ComputeLevel(ref a, ref b, count * steep);//计算还剩下的距离

            if (a != 0 && b != 0)
            {
                c = Math.Min(Math.Abs(a), Math.Abs(b));
                data.Add(GetSteep(a, b, c));
                ComputeLevel(ref a, ref b, c);//计算还剩下的距离
            }

            count = Math.Max(Math.Abs(a) / steep, Math.Abs(b) / steep);

            for (int i = 0; i < count; i++)
            {
                data.Add(GetSteep(a, b, steep));
            }
            ComputeLevel(ref a, ref b, count * steep);
            c = Math.Max(Math.Abs(a), Math.Abs(b));
            data.Add(GetSteep(a, b, c));

            var datas = Tools.Contact(new byte[] { 0x00, 0x01, 0x8B, 0x51 }, net.GetNetworkBytes(locationX),
                net.GetNetworkBytes(locationY),
                net.GetNetworkBytes((short)data.Count), data.ToArray());
            datas = Tools.Contact(net.GetNetworkBytes(datas.Length), datas);
            return datas;
        }

        internal static byte[] GetWalkData(Point Location, short x, short y, int steep)
        {
            throw new NotImplementedException();
        }

        public static byte[] GetChangeLine(int lineNumber)
        {
            var data = Commands.GetCommand("换线");
            return Tools.Contact(new byte[] { 0x00, 0x00, 0x00, 0x06 }, data.Data, new byte[] { (byte)(lineNumber * 2), 01 });
        }

        public static List<byte[]> GetRevive()
        {
            List<byte[]> list = new List<byte[]>();
            //list.Add(new byte[] { 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x0F, 0xCA });
            //list.Add(new byte[] { 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0xCC, 0xE1, 0x00, 0x00, 0x00, 0x4F });
            //list.Add(new byte[] { 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x93, 0x21 });
            //list.Add(new byte[] { 0x00, 0x00, 0x00, 0x0C, 0x00, 0x01, 0x8B, 0x57, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x03, 0xEA });
            //list.Add(new byte[] { 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x8B, 0x5B });
            list.Add(new byte[] { 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x93, 0x21 });
            list.Add(new byte[] { 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x8B, 0x57, 0xC0, 0x16, 0xA4, 0x0C });
            list.Add(new byte[] { 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x8B, 0x5B });
            return list;
        }

        public static byte[] GetAttactData(Player player, Monster monster, Skill skill)
        {
            return attactDataPacker[skill.Name].GetData(player.CurrentMap, player, monster);
        }

        /// <summary>
        /// 获取购买药品数据
        /// </summary>
        /// <param name="item"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static byte[] GetBuyMedicinalData(Medicinal item, int count)
        {
            return item.Data;//直接返回购买1个药品的数据包
            var data = new byte[] { 0x00, 0x00, 0x00, 0x19, 0x00, 0x01, 0x9A, 0xF1, 0xA0, 0x9C, 0x01 };
            return data = Tools.Contact(data, new byte[] { item.Type }, new byte[] { 0x02, 0x02 }, item.Type1, item.Gold, new byte[] { 0x0A, 0x14, 0x90, 0x4E, 0xD8, 0x04, 0xB0, 0x09, 0x02, 0x06 });
        }

        public static byte[] GetUseItemData(Player player, Thing item)
        {
            var data = new byte[] { 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01, 0x97, 0x0B };
            data = Tools.Contact(data, GetNetworkData(item.InstanceID), player.Version, new byte[] { 0x02 });
            return data;
        }

        public static byte[] GetUsePackageData(Player player, Thing item)
        {
            var data = new byte[] { 0x00, 0x01, 0x97, 0x0B };
            data = Tools.Contact(data, GetNetworkData(item.InstanceID), new byte[] { 0x7a, 0x02 });
            data = Tools.Contact(GetNetworkData(data.Length), data);
            return data;
        }

        public static byte[] GetEquipItemData(Thing item)
        {
            var data = new byte[] { 0x00, 0x00, 0x00, 0x0D, 0x00, 0x01, 0x9E, 0xD9 };
            data = Tools.Contact(data, GetNetworkData(item.InstanceID), new byte[] { 0x0c });
            return data;
        }

        public static byte[] GetOpenMailData(Player player, long InstanceID)
        {
            var data = new byte[] {  0x00, 0x01, 0xE4, 0xF9 };
            data = Tools.Contact(data, GetNetworkData(InstanceID), new byte[] { 0x7a, 0x01 });
            data = Tools.Contact(GetNetworkData(data.Length), data);
            return data;
        }

        public static byte[] GetTiLianData(Thing item)
        {
            var data = new byte[] { 0x00, 0x00, 0x00, 0x10, 0x00, 0x07, 0xCC, 0xED, 0x00, 0x01 };
            data = Tools.Contact(data, GetNetworkData(item.InstanceID), new byte[] { 0x00, 0x00 });
            return data;
        }

        public static byte[] GetZhuangBeiData(long InstanceID, byte[] version, byte i)
        {
            var data = new byte[] { 0x00, 0x01, 0x9e, 0xd9 };
            var data1 = new byte[] { i };
            data = Tools.Contact(data, GetNetworkData(InstanceID), version, data1);
            data = Tools.Contact(GetNetworkData(data.Length), data);
            return data;
        }

        /// <summary>
        /// 获取领取精魄数据包
        /// </summary>
        /// <returns></returns>
        public static byte[] GetJingPoData()
        {
            return new byte[] { 00, 0x00, 0x00, 0x04, 0x00, 0x09, 0x28, 0x89 };
        }

        public static byte[] GetCreateCharacterData(string name, ProfessionEnum profession = ProfessionEnum.弓手)
        {
            byte[] data = { 0x00, 0x01, 0x87, 0x6B };
            var nameByte = Encoding.UTF8.GetBytes(name);
            //var nameByte = Encoding.UTF8.GetBytes("金币是QQ");
            data = Tools.Contact(data, GetNetworkData((short)nameByte.Length), nameByte,
                GetNetworkData((short)profession), new byte[] { 0x00, 0x00, 0x00, 0x00, 0x1F, 0x7B, 0x22, 0x75, 0x73, 0x65, 0x72, 0x5F, 0x72, 0x65, 0x66, 0x65, 0x72, 0x22, 0x3A, 0x22, 0x22, 0x2C, 0x22, 0x63, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x22, 0x3A, 0x22, 0x30, 0x22, 0x7D });
            data = Tools.Contact(GetNetworkData(data.Length), data);
            return data;
        }

        public static Message GetMessage(byte[] data)
        {
            int index = 0;
            int id = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data, index));
            index += 4;
            //if (id == Message.Text)
            //{
            //    id = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data, index));
            //    index += 4;
            //    if (((MainConfig)ConfigManager.ApplicationConfig).LogServerInfo)
            //    {
            //        ConsoleBLL.WriteLineWaring(Tools.GetHexString(data, data.Length));
            //        ConsoleBLL.WriteLineWaring(Tools.ConvertChar(Tools.GetString(data, data.Length)));
            //    }
            //}
            Message message = new Message();

            message.MessageType = (MessageTypeEnum)id;
            message.Data = data.Skip(index).ToArray();
            message.Length = message.Data.Length;
            return message;
        }

        public static byte[] GetPointData(Point p)
        {
            return Tools.Contact(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)(p.X * 25))), BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)(p.Y * 25))));
        }

        public static byte[] GetPointData(short x, short y)
        {
            return Tools.Contact(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(x)), BitConverter.GetBytes(IPAddress.HostToNetworkOrder(y)));
        }

        public static byte[] GetNetworkData(short data)
        {
            return net.GetNetworkBytes(data);
        }

        public static byte[] GetNetworkData(int data)
        {
            return net.GetNetworkBytes(data);
        }

        public static byte[] GetNetworkData(long data)
        {
            return net.GetNetworkBytes(data);

        }

        public static short GetHostData16(byte[] data, int startIndex)
        {
            return net.GetHostInt16(data, startIndex);
        }

        public static int GetHostData32(byte[] data, int startIndex)
        {
            return net.GetHostInt32(data, startIndex);
        }

        public static long GetHostData64(byte[] data, int startIndex)
        {
            return net.GetHostInt64(data, startIndex);
        }

        #region 计算路径坐标
        private static byte GetSteep(int a, int b, int steep)
        {
            int result = 0;
            if (a < 0)
            {
                if (b < 0)
                {
                    result = 0xe0 + steep;
                }
                else if (b == 0)
                {
                    result = 0xc0 + steep;
                }
                else
                {
                    result = 0xa0 + steep;
                }
            }
            else if (a == 0)
            {
                if (b < 0)
                {
                    return (byte)steep;
                }
                else if (b == 0)
                {
                    result = 0x60;
                }
                else
                {
                    result = 0x80 + steep;
                }
            }
            else
            {
                if (b < 0)
                {
                    result = 0x20 + steep;
                }
                else if (b == 0)
                {
                    result = 0x40 + steep;
                }
                else
                {
                    result = 0x60 + steep;
                }
            }

            return (byte)result;
        }
        private static void ComputeLevel(ref int a, ref int b, int steep)
        {
            if (a < 0)
            {
                a += steep;
            }
            else if (a > 0)
            {
                a -= steep;
            }
            if (b < 0)
            {
                b += steep;
            }
            else if (b > 0)
            {
                b -= steep;
            }
        }
        #endregion

        internal static byte[] GetAttactData(Player player, List<Monster> monsters, Skill skill)
        {
            if (monsters.Count == 1)
            {
                return attactDataPacker[skill.Name].GetData(player.CurrentMap, player, monsters[0]);
            }
            else
            {
                return attactDataPacker[skill.Name].GetData(player.CurrentMap, player, monsters);
            }
        }

        internal static byte[] GetItemData(Player player, Thing item)
        {
            var data = new byte[] { 0x00, 0x01, 0x97, 0x13, 0x00, 0x01 };
            data = Tools.Contact(data, DataPackager.GetNetworkData(item.InstanceID), player.Version);
            return Tools.Contact(DataPackager.GetNetworkData(data.Length), data);
        }

        internal static byte[] GetItemData(long instanceID)
        {
            var data = new byte[] { 0x00, 0x01, 0x97, 0x13, 0x00, 0x01 };
            data = Tools.Contact(data, DataPackager.GetNetworkData(instanceID));
            return Tools.Contact(DataPackager.GetNetworkData(data.Length), data);
        }

        internal static byte[] GetRideData()
        {
            return new byte[] { 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0xEC, 0xFA, 0x00, 0x03, 0x00 };
        }

        internal static byte[] GetSellData(Player player, Thing item)
        {
            var data = new byte[] { 0x00, 0x01, 0x9A, 0xF7, 0x00, 0x01 };
            data = Tools.Contact(data, DataPackager.GetNetworkData(item.InstanceID), player.Version);
            return Tools.Contact(DataPackager.GetNetworkData(data.Length), data);
        }

        internal static byte[] GetSellData1(Player player, long InstanceID)
        {
            var data = new byte[] { 0x00, 0x01, 0x9A, 0xF7, 0x00, 0x01 };
            data = Tools.Contact(data, DataPackager.GetNetworkData(InstanceID), player.Version);
            return Tools.Contact(DataPackager.GetNetworkData(data.Length), data);
        }

        internal static byte[] GetAddPointData()
        {
            //00 00 00 09 00 01 95 D2 02 00 00 00 00 	 加1力量 第9位是点数
            //00 00 00 09 00 01 95 D2 00 00 08 00 00 	 加4敏捷 11位是点数
            return new byte[] { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x95, 0xD2, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x95, 0xD2, 0x00, 0x00, 0x08, 0x00, 0x00 };
        }
    }
}
